/**
 * Facultad de Ingeniería - Universidad de Buenos Aires
 * 75.41 - Algoritmos y Programación II
 * Archivo de Texto (implementación)
 * Cátedra Ing. Patricia Calvo
 * v1.0
 * Autor: Mariano Simone (marianosimone+7541@gmail.com)
 **/

#include <iostream>

//Inclusiones necesarias
#include "archivoTexto.h"

using namespace std;

ArchivoTexto::ArchivoTexto(const std::string& path) {
  //intenta abrir el archivo en modo lectura - escritura
  archivo.open(path.c_str(), std::fstream::in | std::fstream::out);

  if (!archivo.is_open()) {
    //si no hubo éxito en la apertura...
    //limpia los flags de control de estado del archivo
    archivo.clear();

    //crea el archivo
    archivo.open(path.c_str(), std::fstream::out);
    archivo.close();

    //reabre el archivo para lectura - escritura
    archivo.open(path.c_str(), std::fstream::in | std::fstream::out);

    if (!archivo.is_open())
      // si no se pudo crear el archivo arroja una excepción/
      throw std::ios_base::failure("El archivo no pudo ser abierto");
  }
}

ArchivoTexto::~ArchivoTexto() {
  archivo.close();
}

void ArchivoTexto::escribir(char c) {
  // Intenta escribir el caracter en el archivo
  archivo.put(c);

  if (archivo.fail())
    //si se produjo un error, arroja una excepción
    throw std::ios_base::failure("No se pudo escribir correctamente el registro");
}

void ArchivoTexto::escribir(const std::string& cadena) {
  //intenta escribir la cadena en el archivo
  archivo << cadena;
  if (archivo.fail())
    // si se produjo un error, arroja una excepción
    throw std::ios_base::failure("No se pudo escribir correctamente la cadena");
}

void ArchivoTexto::terminarLinea() {
  // intenta escribir en el archivo
  archivo << endl;

  if (archivo.fail())
    //si se produjo un error, arroja una excepción
    throw std::ios_base::failure("No se pudo terminar la linea");
}

void ArchivoTexto::tabular() {
  escribir('\t');
}

bool ArchivoTexto::leerLinea(std::string &cadena) {
  char linea[MAX_LENGTH];

  // lee del archivo a la linea, hasta haber leido:
  // MAX_LENGTH caracteres, o un fin de linea
  archivo.getline( (char*)&linea , MAX_LENGTH , '\n');
  cadena = linea;

  if (archivo.fail() ) {
    //chequea si se ha producido un error, se devuelve false
    archivo.clear();
    return false;
  }
  return true;
}

/**
 * Posiciona el cursor al comienzo del archivo
 */
void ArchivoTexto::irAlPrincipio() {
  archivo.tellg();
  archivo.clear();
  archivo.seekg(0);
  archivo.seekp(0);
  archivo.tellg();
}

/**
 * Posiciona el cursor al final del archivo
 */
void ArchivoTexto::irAlFinal() {
  archivo.tellg();
  archivo.clear();
  archivo.seekg(0, ios::end);
  archivo.seekp(0, ios::end);
  archivo.tellg();
}

/**
   * [Agregado IH][ALGOII - TP0]:
   * Lee del archivo una cadena de caracteres en sentido inverso, a partir de la posición actual del cursor y hasta:
   *  - Que se encuentre un fin de linea
   *  - Se lean MAX_LENGTH caracteres
   *  - Se encuentre el principio del archivo
   * El contenido leido se almacena en el parámetro "cadena"
   * Retorna true si pudo leer una linea, o false en caso contrario
   */
bool ArchivoTexto::leerLineaHaciaAtras(std::string &cadena) {

    char linea[MAX_LENGTH];
    int miCursor;
    char c;
    int i;

    //Guardo la posision en la que está el cursor de lectura
    miCursor=archivo.tellg();

    //Si esta posisionado antes del inicio no puedo leer (condición de corte)
    if (miCursor<0)
        return false;


    //leo el caracter
    c = archivo.get();

    // Tratamiento especial para puntero en EOF:
    // si el archivo estaba parado en EOF la lectura fue erronea
    // si ese era el caso leo el caracter anterior a EOF
    if (archivo.fail())
    {
        if (archivo.eofbit)
        {

            //limpio los flags
            archivo.clear();

            //posiciono el cursor antes del EOF
            archivo.seekg(-1,ios_base::end);

            //Guardo la posicion para futuras lecturas
            miCursor = archivo.tellg();

            //El archivo esta vacío
            if (miCursor<0)
                return false;

            //posicionado en EOF-1, leo el caracter
            c = archivo.get();

        }

    }

    //Luego de la lectura del caracter, retrocedo el puntero a la posicion anterior de la últma lectura
    archivo.seekg(--miCursor);


    //Bucle para leer todos los demas caracteres de la línea (ya tengo el primero leído)
    i = 0;
    while (c!= '\n' && miCursor >= 0 && i < MAX_LENGTH)
    {
        //guardo el caracter leído en el array
        linea[i++] = c;

       //Antes de cada lectura guardo la posicion del cursor
        miCursor = archivo.tellg();

        //leo el caracter
        c = archivo.get();

        //llevo el cursor a la posicion anterior al último caracter leído
        archivo.seekg(--miCursor);

    }

    //Al llegar al principio del archivo agrego el último caracter
    if (miCursor<=0 && c!='\n')
    {
        linea[i++] = c;
    }

    //Ya leí todos los caracteres de la línea
    //marco el fin del string
    linea[i] = 0;

    //seteo el string de retorno
    cadena = linea;

    //Posisiono el cursor antes del endl para futuras lecturas (descarto el enter igual que el getline)
    if (c == '\n' && miCursor>0)
    {
        archivo.seekg(--miCursor);
    }

    return true;
}
